#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
股票交易分析系统 - Web服务启动脚本
提供开发和生产环境的启动选项
"""

import argparse
import os
import sys
import subprocess
import logging
import signal
import psutil
import time
from pathlib import Path

def setup_logging():
    """设置日志"""
    logging.basicConfig(
        level=logging.INFO,
        format='%(asctime)s - %(levelname)s - %(message)s'
    )
    return logging.getLogger(__name__)

def check_dependencies():
    """检查依赖是否安装"""
    logger = logging.getLogger(__name__)
    
    try:
        import fastapi
        import uvicorn
        import jinja2
        logger.info("✅ Web框架依赖检查通过")
        return True
    except ImportError as e:
        logger.error(f"❌ 缺少依赖: {e}")
        logger.error("请运行: pip install -r requirements.txt")
        return False

def check_database_connection():
    """检查数据库连接"""
    logger = logging.getLogger(__name__)
    
    try:
        from repositories.database_factory import database_factory
        if database_factory.validate_all_connections():
            logger.info("✅ 数据库连接检查通过")
            return True
        else:
            logger.error("❌ 数据库连接验证失败")
            return False
    except Exception as e:
        logger.error(f"❌ 数据库连接失败: {e}")
        return False

def start_development_server(host="127.0.0.1", port=8000, reload=True, log_level="info"):
    """启动开发服务器"""
    logger = logging.getLogger(__name__)
    
    logger.info("🚀 启动开发服务器...")
    logger.info(f"📍 访问地址: http://{host}:{port}")
    logger.info("🔄 自动重载: 已启用")
    logger.info("⏹️  按 Ctrl+C 停止服务器")
    
    try:
        import uvicorn
        uvicorn.run(
            "web_app:app",
            host=host,
            port=port,
            reload=reload,
            log_level=log_level,
            access_log=True
        )
    except KeyboardInterrupt:
        logger.info("🛑 服务器已停止")
    except Exception as e:
        logger.error(f"❌ 服务器启动失败: {e}")
        sys.exit(1)

def start_production_server(host="0.0.0.0", port=8000, workers=1):
    """启动生产服务器"""
    logger = logging.getLogger(__name__)
    
    logger.info("🏭 启动生产服务器...")
    logger.info(f"📍 访问地址: http://{host}:{port}")
    logger.info(f"👥 工作进程数: {workers}")
    logger.info("⏹️  按 Ctrl+C 停止服务器")
    
    try:
        import uvicorn
        uvicorn.run(
            "web_app:app",
            host=host,
            port=port,
            workers=workers,
            log_level="warning",
            access_log=False
        )
    except KeyboardInterrupt:
        logger.info("🛑 服务器已停止")
    except Exception as e:
        logger.error(f"❌ 服务器启动失败: {e}")
        sys.exit(1)

def start_with_docker():
    """使用Docker启动"""
    logger = logging.getLogger(__name__)
    
    logger.info("🐳 使用Docker启动服务...")
    
    # 检查Docker是否安装
    try:
        subprocess.run(["docker", "--version"], check=True, capture_output=True)
    except (subprocess.CalledProcessError, FileNotFoundError):
        logger.error("❌ Docker未安装或不可用")
        sys.exit(1)
    
    # 构建并启动容器
    try:
        logger.info("📦 构建Docker镜像...")
        subprocess.run(["docker-compose", "build"], check=True)
        
        logger.info("🚀 启动Docker容器...")
        subprocess.run(["docker-compose", "up", "-d"], check=True)
        
        logger.info("✅ 服务已启动")
        logger.info("📍 访问地址: http://localhost:8000")
        logger.info("🔍 查看日志: docker-compose logs -f")
        logger.info("🛑 停止服务: docker-compose down")
        
    except subprocess.CalledProcessError as e:
        logger.error(f"❌ Docker启动失败: {e}")
        sys.exit(1)

def get_service_pid(port=8000, prefer_python=True):
    """获取指定端口上运行的服务PID"""
    import subprocess
    import re
    
    found_pids = []
    
    try:
        # 方法1: 使用系统命令 lsof (macOS/Linux) - 最准确
        if sys.platform != 'win32':
            result = subprocess.run(['lsof', '-ti', f':{port}'], 
                                  capture_output=True, text=True, timeout=5)
            if result.returncode == 0 and result.stdout.strip():
                pids = [int(pid) for pid in result.stdout.strip().split('\n') if pid.isdigit()]
                found_pids.extend(pids)
    except (subprocess.TimeoutExpired, subprocess.CalledProcessError, ValueError, FileNotFoundError):
        pass
    
    try:
        # 方法2: 使用psutil
        for conn in psutil.net_connections(kind='inet'):
            if conn.laddr.port == port and conn.status == 'LISTEN' and conn.pid:
                if conn.pid not in found_pids:
                    found_pids.append(conn.pid)
    except (psutil.NoSuchProcess, psutil.AccessDenied, psutil.ZombieProcess):
        pass
    
    # 如果找到多个PID，优先返回Python进程
    if found_pids and prefer_python:
        for pid in found_pids:
            try:
                process = psutil.Process(pid)
                if 'python' in process.name().lower():
                    return pid
            except (psutil.NoSuchProcess, psutil.AccessDenied):
                continue
    
    # 返回第一个找到的PID
    return found_pids[0] if found_pids else None

def get_all_service_pids(port=8000):
    """获取指定端口上运行的所有服务PID"""
    import subprocess
    
    found_pids = []
    
    try:
        # 使用lsof获取所有PID
        if sys.platform != 'win32':
            result = subprocess.run(['lsof', '-ti', f':{port}'], 
                                  capture_output=True, text=True, timeout=5)
            if result.returncode == 0 and result.stdout.strip():
                pids = [int(pid) for pid in result.stdout.strip().split('\n') if pid.isdigit()]
                found_pids.extend(pids)
    except (subprocess.TimeoutExpired, subprocess.CalledProcessError, ValueError, FileNotFoundError):
        pass
    
    return found_pids

def stop_service(port=8000):
    """停止指定端口上的服务"""
    logger = logging.getLogger(__name__)
    
    # 获取所有相关的PID
    all_pids = get_all_service_pids(port)
    python_pid = get_service_pid(port, prefer_python=True)
    
    if not all_pids:
        logger.info(f"ℹ️  端口 {port} 上没有运行的服务")
        return True
    
    logger.info(f"🔍 发现端口 {port} 上有 {len(all_pids)} 个进程:")
    
    # 显示所有进程信息
    for pid in all_pids:
        try:
            process = psutil.Process(pid)
            logger.info(f"   PID {pid}: {process.name()} ({'Python服务' if 'python' in process.name().lower() else '其他进程'})")
        except (psutil.NoSuchProcess, psutil.AccessDenied):
            logger.info(f"   PID {pid}: 进程信息获取失败")
    
    # 优先停止Python进程
    if python_pid:
        logger.info(f"🛑 正在停止Python服务 (PID: {python_pid})...")
        if _stop_single_process(python_pid, logger):
            logger.info("✅ Python服务已停止")
            
            # 检查是否还有其他进程占用端口
            remaining_pids = get_all_service_pids(port)
            if not remaining_pids:
                return True
            else:
                logger.info(f"⚠️  端口 {port} 仍被其他进程占用")
        else:
            logger.error("❌ Python服务停止失败")
    
    # 停止所有其他进程（谨慎操作）
    logger.warning("⚠️  检测到非Python进程占用端口，这可能不是我们的Web服务")
    logger.info("💡 建议手动检查: lsof -i :8000")
    
    return python_pid is not None

def _stop_single_process(pid, logger):
    """停止单个进程"""
    try:
        process = psutil.Process(pid)
        
        # 尝试优雅关闭
        process.terminate()
        
        # 等待进程结束
        try:
            process.wait(timeout=5)
            return True
        except psutil.TimeoutExpired:
            # 强制关闭
            logger.warning(f"⚠️  PID {pid} 优雅停止超时，强制关闭...")
            process.kill()
            return True
            
    except (psutil.NoSuchProcess, psutil.AccessDenied) as e:
        logger.error(f"❌ 停止进程 {pid} 失败: {e}")
        return False

def restart_service(host="127.0.0.1", port=8000, mode="dev"):
    """重启服务"""
    logger = logging.getLogger(__name__)
    
    logger.info("🔄 重启服务...")
    
    # 先停止服务
    if stop_service(port):
        time.sleep(2)  # 等待端口释放
        
        # 重新启动
        if mode == "dev":
            start_development_server(host, port, reload=True)
        else:
            start_production_server(host, port, workers=1)
    else:
        logger.error("❌ 重启失败：无法停止现有服务")

def show_service_status(port=8000):
    """显示服务状态"""
    logger = logging.getLogger(__name__)
    
    logger.info("=" * 50)
    logger.info("📊 服务状态检查")
    logger.info("=" * 50)
    
    all_pids = get_all_service_pids(port)
    python_pid = get_service_pid(port, prefer_python=True)
    
    if not all_pids:
        logger.info(f"❌ 端口 {port} 上没有运行的服务")
    else:
        logger.info(f"🔍 端口 {port} 上发现 {len(all_pids)} 个进程:")
        
        for i, pid in enumerate(all_pids, 1):
            try:
                process = psutil.Process(pid)
                is_python = 'python' in process.name().lower()
                status_icon = "🐍" if is_python else "📱"
                service_type = "Python Web服务" if is_python else "其他应用"
                
                logger.info(f"")
                logger.info(f"{status_icon} 进程 #{i} ({'主要服务' if pid == python_pid else '相关进程'})")
                logger.info(f"   PID: {pid}")
                logger.info(f"   进程名: {process.name()}")
                logger.info(f"   类型: {service_type}")
                logger.info(f"   启动时间: {time.ctime(process.create_time())}")
                logger.info(f"   内存使用: {process.memory_info().rss / 1024 / 1024:.1f} MB")
                logger.info(f"   CPU使用: {process.cpu_percent():.1f}%")
                
                if is_python:
                    logger.info(f"   🌐 访问地址: http://127.0.0.1:{port}")
                    
            except (psutil.NoSuchProcess, psutil.AccessDenied):
                logger.warning(f"⚠️  PID {pid} 进程信息获取失败")
        
        if python_pid:
            logger.info(f"")
            logger.info(f"✅ Python Web服务正在运行 (PID: {python_pid})")
        else:
            logger.info(f"")
            logger.info(f"⚠️  未检测到Python Web服务，端口可能被其他应用占用")
    
    logger.info("=" * 50)

def start_background_service(host="127.0.0.1", port=8000, mode="dev"):
    """后台启动服务"""
    logger = logging.getLogger(__name__)
    
    # 检查是否已有服务运行
    if get_service_pid(port):
        logger.warning(f"⚠️  端口 {port} 已被占用，请先停止现有服务")
        return False
    
    logger.info(f"🚀 后台启动服务 (端口: {port})...")
    
    # 构建启动命令
    script_path = os.path.abspath(__file__)
    cmd = [
        sys.executable, script_path,
        "--mode", mode,
        "--host", host,
        "--port", str(port),
        "--skip-checks"
    ]
    
    try:
        # 后台启动
        process = subprocess.Popen(
            cmd,
            stdout=subprocess.DEVNULL,
            stderr=subprocess.DEVNULL,
            start_new_session=True
        )
        
        # 等待服务启动
        time.sleep(3)
        
        if get_service_pid(port):
            logger.info("✅ 服务已在后台启动")
            logger.info(f"   访问地址: http://{host}:{port}")
            logger.info(f"   使用 'python {__file__} --action status --port {port}' 查看状态")
            logger.info(f"   使用 'python {__file__} --action stop --port {port}' 停止服务")
            return True
        else:
            logger.error("❌ 后台启动失败")
            return False
            
    except Exception as e:
        logger.error(f"❌ 后台启动失败: {e}")
        return False

def main():
    """主函数"""
    parser = argparse.ArgumentParser(description="股票交易分析系统 Web服务启动器")
    
    # 服务管理动作
    parser.add_argument("--action", choices=["start", "stop", "restart", "status", "background"], 
                       default="start", help="服务管理动作")
    
    # 运行配置
    parser.add_argument("--mode", choices=["dev", "prod", "docker", "debug"], default="dev",
                       help="运行模式: dev(开发), prod(生产), docker(Docker), debug(程序调试)")
    parser.add_argument("--host", default="127.0.0.1", help="绑定主机地址")
    parser.add_argument("--port", type=int, default=8000, help="端口号")
    parser.add_argument("--workers", type=int, default=1, help="工作进程数(仅生产模式)")
    parser.add_argument("--no-reload", action="store_true", help="禁用自动重载(仅开发模式)")
    parser.add_argument("--skip-checks", action="store_true", help="跳过启动前检查")
    
    args = parser.parse_args()
    
    # 设置日志
    logger = setup_logging()
    
    logger.info("=" * 60)
    logger.info("🎯 股票交易分析系统 - Web服务启动器")
    logger.info("=" * 60)
    
    # 处理服务管理动作
    if args.action == "stop":
        stop_service(args.port)
        return
    elif args.action == "status":
        show_service_status(args.port)
        return
    elif args.action == "restart":
        restart_service(args.host, args.port, args.mode)
        return
    elif args.action == "background":
        start_background_service(args.host, args.port, args.mode)
        return
    
    # 默认启动动作
    # 启动前检查
    if not args.skip_checks:
        logger.info("🔍 执行启动前检查...")
        
        if not check_dependencies():
            sys.exit(1)
            
        if not check_database_connection():
            logger.warning("⚠️  数据库连接失败，但仍可启动服务")
    
    # 根据模式启动服务
    if args.mode == "dev":
        if args.host == "127.0.0.1":
            logger.info("🔧 开发模式 - 仅本地访问")
        else:
            logger.info("🔧 开发模式 - 允许外部访问")
        start_development_server(
            host=args.host,
            port=args.port,
            reload=not args.no_reload
        )
    elif args.mode == "prod":
        logger.info("🏭 生产模式")
        start_production_server(
            host=args.host,
            port=args.port,
            workers=args.workers
        )
    elif args.mode == "debug":
        logger.info("🐛 调试模式 - 程序调试支持")
        logger.info("📍 访问地址: http://{}:{}".format(args.host, args.port))
        logger.info("🔍 可以使用IDE断点调试")
        logger.info("⏹️  按 Ctrl+C 停止服务器")
        
        # 直接运行FastAPI应用，不使用uvicorn的自动重载
        # 这样可以支持IDE调试器
        try:
            import uvicorn
            # 使用uvicorn.run但禁用自动重载，支持调试器
            uvicorn.run(
                "web_app:app",
                host=args.host,
                port=args.port,
                reload=False,  # 调试模式下禁用自动重载
                log_level="info",
                access_log=True,
                use_colors=True
            )
        except KeyboardInterrupt:
            logger.info("🛑 调试服务器已停止")
        except Exception as e:
            logger.error(f"❌ 调试服务器启动失败: {e}")
            sys.exit(1)
    elif args.mode == "docker":
        start_with_docker()

if __name__ == "__main__":
    main()
